#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>

int S1[4][4][2]={{{0,1},{0,0},{1,1},{1,0}},
                 {{1,1},{1,0},{0,1},{0,0}},
                 {{0,0},{1,0},{0,1},{1,1}},
                 {{1,1},{0,1},{0,0},{1,0}}};
int S2[4][4][2]={{{0,0},{0,1},{1,0},{1,1}},
                 {{1,0},{0,0},{0,1},{1,1}},
                 {{1,1},{1,0},{0,1},{0,0}},
                 {{1,0},{0,1},{0,0},{1,1}}};

//1.1.1 从键盘输入文件到文本文件中
void Input()
{
    FILE *fp;
    char ch;
    fp=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-1.txt","w");
    printf("[INPUT]请输入文本:");
    ch=getchar();
    while(ch!='\n'){
        fputc(ch,fp);
        ch=getchar();
    }
    fclose(fp);
}

//1.1.2 将文件中的ASCII字符转换为二进制（类itoa函数）
char* ToBinary(int num)   //其实可以调用itoa函数，但是需要额外的头文件支持
{
    int i=0,j=0,k=0;
    char result[8];
    char *output;
    while (num != 0){
        result[i++]=(num%2==0?'0':'1');
        num/= 2;
    }
    output=(char*)malloc(8*sizeof(char));
    for(i=7,j=0;;i--,j++){
        if(result[j]=='\0'){
            for(k=i;k>=0;k--)  output[k]='0';
            break;
        }
        output[i]=result[j];
    }
    return output;
}

//1.1.3 将二进制转换为文件中的ASCII字符（类itoa函数）
char ToAscil(char ascii[8])   //其实可以调用itoa函数，但是需要额外的头文件支持
{
    int num=0;
    for(int i=0;i<=7;i++){
        num=num*2;
        num+=(ascii[i]-'0');
    }
    return (char)num;
}

//1.1.4 将文件中的字符读入并驱动进行二进制转换
void ReadToAscil()
{
    Input();
    FILE *in,*out;
    char ch;
    char *temp;
    int mode,countnum;
    in=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-1.txt","r");
    out=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-2.txt","w");
    if(in==NULL)
    {
        printf("[ERROR]无法打开文件\n");
        exit(0);
    }
    if(out==NULL)
    {
        printf("[ERROR]无法写入文件\n");
        exit(0);
    }
    ch=fgetc(in);
    while(ch!=EOF)
    {
        temp=(char*)malloc(10*sizeof(char));
        temp=ToBinary((int)ch);
        temp[8]='\0';
        fputs(temp,out);
        ch=fgetc(in);
    }
    fclose(in);
    fclose(out);
}

//1.1.5 将二进制读入并驱动字符转换
void AscilToWrite()
{
    FILE *in,*out;
    char temp[9],output;
    in=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-4.txt","r");
    out=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-5.txt","w");
    if(in==NULL)
    {
        printf("[ERROR]无法打开文件\n");
        exit(0);
    }
    if(out==NULL)
    {
        printf("[ERROR]无法写入文件\n");
        exit(0);
    }
    printf("[OUTPUT]解密的文本为:");
    while(fgets(temp,9,in))
    {
        output=ToAscil(temp);
        fputc(output,out);
        putchar(output);
    }
    printf("\n");
    fclose(in);
    fclose(out);
}

//1.1.6 S-DES生成密钥
void CreateKey(int k[11],int k1[9],int k2[9])
{
    int temp[11];
    //P10置换
    temp[1]=k[3],temp[2]=k[5],temp[3]=k[2],temp[4]=k[7],temp[5]=k[4],
    temp[6]=k[10],temp[7]=k[1],temp[8]=k[9],temp[9]=k[8],temp[10]=k[6];
    int l[6],r[6];
    for(int i=1;i<=5;i++)    l[i]=temp[i],r[i]=temp[i+5];
    int x1,x2,x3,x4;
    x1=l[1],x2=r[1];
    for(int i=2;i<=5;i++)    l[i-1]=l[i],r[i-1]=r[i];
    l[5]=x1;  r[5]=x2;
    for(int i=1;i<=5;i++)    temp[i]=l[i],temp[i+5]=r[i];
    k1[1]=temp[6],k1[2]=temp[3],k1[3]=temp[7],k1[4]=temp[4],k1[5]=temp[8],k1[6]=temp[5],k1[7]=temp[10],k1[8]=temp[9];
    printf("[INFO]密钥K1:");
    int ans=0;
    for(int i=1;i<=8;i++)
    {
        ans+=k1[i]*(1<<(8-i));
        printf("%d",k1[i]);
    }
    printf("\n");
    x1=l[1],x2=l[2],x3=r[1],x4=r[2];
    for(int i=2;i<=5;i++)     l[i-2]=l[i],r[i-2]=r[i];
    l[4]=x1,l[5]=x2;
    r[4]=x3,r[5]=x4;
    for(int i=1;i<=5;i++)     temp[i]=l[i],temp[i+5]=r[i];
    k2[1]=temp[6],k2[2]=temp[3],k2[3]=temp[7],k2[4]=temp[4],k2[5]=temp[8],k2[6]=temp[5],k2[7]=temp[10],k2[8]=temp[9];
    printf("[INFO]密钥K2:");
    ans=0;
    for(int i=1;i<=8;i++)
    {
        ans+=k2[i]*(1<<(8-i));
        printf("%d",k2[i]);
    }
    printf("\n");
}

//1.1.7 f函数
void f(int R[],int K[])
{
    int temp[9];
    temp[1]=R[4],temp[2]=R[1],temp[3]=R[2],temp[4]=R[3],temp[5]=R[2],temp[6]=R[3],temp[7]=R[4],temp[8]=R[1];

    for(int i=1;i<=8;i++)    temp[i]=temp[i]^K[i];

    printf("[INFO]异或结果:");
    int ans=0;
    for(int i=1;i<=8;i++)
    {
        ans+=temp[i]*(1<<(8-i));
        printf("%d",&temp[i]);
    }
    printf("\n");

    int s1[5],s2[5];
    for(int i=1;i<=4;i++)   s1[i]=temp[i],s2[i]=temp[i+4];
    int x1=S1[s1[1]*2+s1[4]][s1[2]*2+s1[3]][0], x2=S1[s1[1]*2+s1[4]][s1[2]*2+s1[3]][1];
    int x3=S2[s2[1]*2+s2[4]][s2[2]*2+s2[3]][0],x4=S2[s2[1]*2+s2[4]][s2[2]*2+s2[3]][1];

    //P4置换
    R[1]=x2,R[2]=x4,R[3]=x3,R[4]=x1;
    printf("[INFO]P4置换结果:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R[i]*(1<<(4-i));
        printf("%d",R[i]);
    }
    printf("\n");
}

//1.1.8 加密主函数
void Encrypt(char text[9],int k1[],int k2[],int temp[9],int ascii[9])
{
    //IP置换（IP={2,6,3,1,4,8,5,7}）
    temp[1]=ascii[i]
    temp[1]=text[2]-'0',temp[2]=text[6]-'0',temp[3]=text[3]-'0',temp[4]=text[1]-'0',
    temp[5]=text[4]-'0',temp[6]=text[8]-'0',temp[7]=text[5]-'0',temp[8]=text[7]-'0';
    printf("[INFO]IP置换:");
    int ans=0;
    for(int i=1;i<=8;i++)
    {
        ans+=temp[i]*(1<<(8-i));
        printf("%d",temp[i]);
    }
    printf("\n");
    int L0[5],R0[5],L1[5],R1[5],L2[5],R2[5];
    for(int i=1;i<=4;i++)
        L0[i]=temp[i],R0[i]=temp[i+4];
    memcpy(L1,R0,sizeof(L1));

    //复合函数fk1
    printf("[INFO]L0:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L0[i]*(1<<(4-i));
        printf("%d",L0[i]);
    }
    printf(" ");

    printf("R0:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R0[i]*(1<<(4-i));
        printf("%d",R0[i]);
    }
    printf("\n");
    f(R0,k1);
    for(int i=1;i<=4;i++)
        R1[i]=L0[i]^R0[i];

    //置换函数
    memcpy(R2,R1,sizeof(R2));

    printf("[INFO]L1:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L1[i]*(1<<(4-i));
        printf("%d",L1[i]);
    }
    printf(" ");

    printf("R1:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R1[i]*(1<<(4-i));
        printf("%d",R1[i]);
    }
    printf("\n");

    //复合函数fk2
    f(R1,k2);
    for(int i=1;i<=4;i++)
        L2[i]=L1[i]^R1[i];

    printf("[INFO]L2:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L2[i]*(1<<(4-i));
        printf("%d",L2[i]);
    }
    printf(" ");

    printf("R2:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R2[i]*(1<<(4-i));
        printf("%d",R2[i]);
    }
    printf("\n");

    temp[1]=L2[4],temp[2]=L2[1],temp[3]=L2[3],temp[4]=R2[1],temp[5]=R2[3],temp[6]=L2[2],temp[7]=R2[4],temp[8]=R2[2];
    printf("[OUTPUT]加密结果:");
    ans=0;

    //IP-1置换
    for(int i=1;i<=8;i++)
    {
        ans+=temp[i]*(1<<(8-i));
        printf("%d",temp[i]);
    }
    printf("\n");
}

//1.1.9 解密主函数
void Decrypt(char text[9],int k1[],int k2[],int temp[9])
{
    //IP置换（IP={2,6,3,1,4,8,5,7}）
    temp[1]=text[2]-'0',temp[2]=text[6]-'0',temp[3]=text[3]-'0',temp[4]=text[1]-'0',
    temp[5]=text[4]-'0',temp[6]=text[8]-'0',temp[7]=text[5]-'0',temp[8]=text[7]-'0';
    printf("[INFO]IP置换:");
    int ans=0;
    for(int i=1;i<=8;i++)
    {
        ans+=temp[i]*(1<<(8-i));
        printf("%d",temp[i]);
    }
    printf("\n");
    int L0[5],R0[5],L1[5],R1[5],L2[5],R2[5];
    for(int i=1;i<=4;i++)
        L0[i]=temp[i],R0[i]=temp[i+4];
    memcpy(L1,R0,sizeof(L1));

    //复合函数fk1
    printf("[INFO]L0:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L0[i]*(1<<(4-i));
        printf("%d",L0[i]);
    }
    printf(" ");

    printf("R0:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R0[i]*(1<<(4-i));
        printf("%d",R0[i]);
    }
    printf("\n");
    f(R0,k2);
    for(int i=1;i<=4;i++)
        R1[i]=L0[i]^R0[i];

    //置换函数
    memcpy(R2,R1,sizeof(R2));

    printf("[INFO]L1:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L1[i]*(1<<(4-i));
        printf("%d",L1[i]);
    }
    printf(" ");

    printf("R1:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R1[i]*(1<<(4-i));
        printf("%d",R1[i]);
    }
    printf("\n");

    //复合函数fk2
    f(R1,k1);
    for(int i=1;i<=4;i++)
        L2[i]=L1[i]^R1[i];

    printf("[INFO]L2:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=L2[i]*(1<<(4-i));
        printf("%d",L2[i]);
    }
    printf(" ");

    printf("R2:");
    ans=0;
    for(int i=1;i<=4;i++)
    {
        ans+=R2[i]*(1<<(4-i));
        printf("%d",R2[i]);
    }
    printf("\n");

    temp[1]=L2[4],temp[2]=L2[1],temp[3]=L2[3],temp[4]=R2[1],temp[5]=R2[3],temp[6]=L2[2],temp[7]=R2[4],temp[8]=R2[2];
    printf("[OUTPUT]解密结果:");
    ans=0;

    //IP-1置换
    for(int i=1;i<=8;i++)
    {
        ans+=temp[i]*(1<<(8-i));
        printf("%d",temp[i]);
    }
    printf("\n");
}

//1.1.10 S-DES主程序
void S_Des()
{
    int mode,flag=0;
    int k[11],k1[9],k2[9],output[9];
    char plaintext[9],ciphertext[9];
    FILE *in,*out;
    printf("[INPUT]请输入主密钥:");
    for(int i=1;i<=10;i++)
    {
        scanf("%1d",&k[i]);
    }
    CreateKey(k,k1,k2);
    printf("[Menu]请选择模式:【0】退出 【1】加密 【2】解密\n");
    printf("[INPUT]请选择模式:");
    scanf("%d",&mode);
    getchar();
    while(1){
        if(mode==1)
        {
            ReadToAscil();
            in=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-2.txt","r");
            out=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-3.txt","w");
            if(in==NULL)
            {
                printf("[ERROR]无法打开文件\n");
                exit(0);
            }
            if(out==NULL)
            {
                printf("[ERROR]无法写入文件\n");
                exit(0);
            }
            while(fgets(plaintext,9,in)){
                for(int i=7;i>=0;i--){
                    plaintext[i+1]=plaintext[i];
                }
                plaintext[0]=0;
                Encrypt(plaintext,k1,k2,output);
                printf("[INFO]加密处理完成！\n");
                for(int i=1;i<=8;i++)   fprintf(out,"%d",output[i]);
            }
            flag=1;
            fclose(in);
            fclose(out);
        }
        else if(mode==2)
        {
            in=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-3.txt","r");
            out=fopen("D:\\Develop\\C-Main\\DS_LiGuohe\\Chapter1\\Chapter1-4.txt","w");
            if(flag!=1){
                printf("[ERROR]还没有加密,请先完成加密操作!");
                exit(0);
            }
            if(in==NULL)
            {
                printf("[ERROR]无法打开文件\n");
                exit(0);
            }
            if(out==NULL)
            {
                printf("[ERROR]无法写入文件\n");
                exit(0);
            }
            while(fgets(plaintext,9,in)){
            for(int i=7;i>=0;i--){
                    plaintext[i+1]=plaintext[i];
                }
                plaintext[0]=0;
                Decrypt(plaintext,k1,k2,output);
                printf("[INFO]解密处理完成！\n");
                for(int i=1;i<=8;i++)   fprintf(out,"%d",output[i]);
            }
            flag=2;
            fclose(in);
            fclose(out);
            AscilToWrite();
        }
        else if(mode==0){
            break;
        }
        else
        {
            printf("[ERROR]输入错误，请重新输入");
        }
        printf("[INPUT]请选择模式:");
        scanf("%d",&mode);
    }
    
}

//1.1.M 主程序
int main()
{
    S_Des();
}